package spring.tx.xml.service.service;

import jakarta.annotation.Resource;
import spring.tx.xml.dao.dao.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * Service层
 * 添加事务：在配置类配置注册事务对象后，可以直接通过注释添加事务
 *
 * @Transactional()
 * 一般统一添加到类上，类下的所有方法都有事务，再对方法单独添加注解指定属性。方法上的注解会覆盖类注解的效果。
 * 也可以单独添加到方法上。
 *
 * 1. 只读模式，用于只做查询操作的语句。
 *      默认为非只读，需要通过属性 @Transactional(readOnly = true) 开启
 *
 * 2. 超时时间，防止应用程序卡住，长时间占用数据库资源。
 *      默认值为-1，表示永远不超时，通过属性 @Transactional(timeout = 3) 开启，单位为秒
 *      超时会回滚事务并释放异常 TransactionTimedOutException
 *
 * 3. 指定触发回滚的异常
 *      默认情况下，发生运行时异常的事务才会回滚 RuntimeException
 *      建议指定Exception异常来控制所有异常都回滚 @Transactional(rollbackFor = Exception.class)
 *      在会触发回滚的异常范围内，可以控制某个异常不回滚 @Transactional(noRollbackFor = FileNotFoundException.class)
 *
 * 4. 设置事务隔离级别
 *      默认为可重复读，推荐设置第二个隔离级别读提交，效率高  @Transactional(isolation = Isolation.READ_COMMITTED)
 *
 * 5. 事务传播行为
 *      定义两个事务操作方法，在顶层方法中调用两个方法 TopService.topService()
 *      通过属性 propagation 指定事务的传播行为，推荐默认值 REQUIRED
 *      propagation = Propagation.REQUIRED 调用方法有事务，就将当前被调用的方法加入到调用方法的事务，否则新建一个事务，最终组成同一个事务
 *      propagation = Propagation.REQUIRES_NEW 不管调用方法是否有事务，当前被调用的方法都是独立的事务
 */

@Transactional(timeout = 3)
@Service
public class StudentService {
    
    @Resource(name = "studentDao")
    private StudentDao studentDao2342;

    // TODO:开启只读模式，会覆盖掉类注释的超时限制
    @Transactional(readOnly = true)
    public void getStudentInfo(){
        //查询 没有必要添加事务！
        //获取学生信息 查询数据库 不修改
    }

    // TODO: 验证默认只有运行时异常事务才回滚，IO异常不会回滚
    public void changeInfoIOException() throws FileNotFoundException {
        // 语句1
        studentDao2342.updateAgeById(99,1);
        // TODO：主动构造IO异常，程序会报错，但事务不会回滚，即 语句1会正常执行，语句2不会执行
        new FileInputStream("xxxx");
        // 语句2
        studentDao2342.updateNameById("test3",1);
    }

    // TODO: 指定回滚的异常、事务隔离级别
    @Transactional(rollbackFor = Exception.class, noRollbackFor = FileNotFoundException.class, isolation = Isolation.READ_COMMITTED)
    public void changeInfo() throws FileNotFoundException {
        // 语句1
        studentDao2342.updateAgeById(99,1);
        // TODO：主动构造IO异常，程序会报错，但事务不会回滚，即语句1会正常执行，语句2不会执行
        new FileInputStream("xxxx");
        // 语句2
        studentDao2342.updateNameById("test3",1);
    }


    // TODO: 事务传播行为验证
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void changeAge(){
        studentDao2342.updateAgeById(998,1);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void changeName(){
        studentDao2342.updateNameById("二狗dan",1);
    }

}

